import pandas as pd


class RecommendationEngine:
    """推荐引擎核心逻辑 - 业务逻辑层"""

    def __init__(self, users_df, products_df, interactions_df):
        self.users = users_df
        self.products = products_df
        self.interactions = interactions_df
        self.user_profiles = self._build_user_profiles()

    def _build_user_profiles(self):
        """构建增强用户画像"""
        profiles = {}
        for _, user in self.users.iterrows():
            # 基础画像
            profile = {
                "base": user.to_dict(),
                "interaction_stats": self._calculate_interaction_stats(user["user_id"])
            }
            profiles[user["user_id"]] = profile
        return profiles

    def _calculate_interaction_stats(self, user_id):
        """计算用户交互统计"""
        user_logs = self.interactions[self.interactions["user_id"] == user_id]

        if user_logs.empty:
            return {
                "total_actions": 0,
                "buy_ratio": 0,
                "preferred_category": None,
                "preferred_flavor": None,
                "preferred_price_range": None
            }

        # 计算购买转化率
        buy_actions = user_logs[user_logs["action"] == "buy"].shape[0]
        total_actions = user_logs.shape[0]
        buy_ratio = buy_actions / total_actions if total_actions > 0 else 0

        # 合并商品信息
        merged = user_logs.merge(self.products, on="product_id")
        if not merged.empty:
            # 计算偏好品类
            category_counts = merged["category"].value_counts()
            preferred_category = category_counts.idxmax() if not category_counts.empty else None

            # 计算口味偏好
            flavor_counts = merged["flavor"].value_counts()
            preferred_flavor = flavor_counts.idxmax() if not flavor_counts.empty else None

            # 计算偏好价格区间
            avg_price = merged["price"].mean()
            if avg_price < 15:
                price_range = "low"
            elif avg_price < 40:
                price_range = "medium"
            else:
                price_range = "high"
        else:
            preferred_category = None
            preferred_flavor = None
            price_range = None

        return {
            "total_actions": total_actions,
            "buy_ratio": buy_ratio,
            "preferred_category": preferred_category,
            "preferred_flavor": preferred_flavor,
            "preferred_price_range": price_range
        }

    def generate_recommendations(self, user_id, top_n=10):
        """生成个性化推荐"""
        if user_id not in self.user_profiles:
            return self._get_fallback_recommendations(top_n)

        profile = self.user_profiles[user_id]
        user_logs = self.interactions[self.interactions["user_id"] == user_id]
        viewed_products = user_logs["product_id"].unique()

        # 候选商品筛选
        candidate_products = self.products.copy()

        # 过滤已交互商品
        candidate_products = candidate_products[~candidate_products["product_id"].isin(viewed_products)]

        # 计算推荐分数
        candidate_products["score"] = candidate_products.apply(
            lambda row: self._calculate_product_score(row, profile),
            axis=1
        )

        # 排序取TopN
        recommendations = candidate_products.sort_values("score", ascending=False).head(top_n)
        return recommendations[["product_id", "name", "category", "flavor", "price", "score"]]

    def _calculate_product_score(self, product, user_profile):
        """计算商品推荐分数"""
        base_profile = user_profile["base"]
        stats = user_profile["interaction_stats"]

        # 1. 基础口味匹配 (20%)
        base_flavor_match = 1 if product["flavor"] == base_profile["preference"] else 0.5

        # 2. 行为口味匹配 (15%)
        behavior_flavor_match = 1 if stats["preferred_flavor"] and product["flavor"] == stats[
            "preferred_flavor"] else 0.7

        # 3. 品类偏好 (20%)
        category_match = 1.5 if stats["preferred_category"] and product["category"] == stats[
            "preferred_category"] else 1

        # 4. 价格敏感度 (20%)
        price_factor = 1
        if base_profile["price_sensitivity"] == "high":
            if product["price"] < 20:
                price_factor = 1.3
            elif product["price"] > 40:
                price_factor = 0.5
        elif base_profile["price_sensitivity"] == "low":
            if product["price"] > 30:
                price_factor = 1.2
            elif product["price"] < 10:
                price_factor = 0.8

        # 5. 商品热度 (10%)
        heat_score = min(1, product["sales"] / 5000)

        # 6. 用户行为权重 (10%)
        behavior_weight = min(1.5, 1 + stats["buy_ratio"] * 2)

        # 7. 新品加成 (5%)
        new_bonus = 1.2 if product["is_new"] else 1

        # 综合得分
        score = (
                        base_flavor_match * 0.2 +
                        behavior_flavor_match * 0.15 +
                        category_match * 0.2 +
                        price_factor * 0.2 +
                        heat_score * 0.1 +
                        behavior_weight * 0.1
                ) * new_bonus

        return round(score, 4)

    def _get_fallback_recommendations(self, top_n):
        """新用户回退推荐策略"""
        # 按热度+评分+新品综合排序
        self.products["fallback_score"] = (
                self.products["sales"] * 0.5 +
                self.products["rating"] * 30 +
                self.products["is_new"] * 20
        )### 牛逼  cnm
        return self.products.sort_values("fallback_score", ascending=False).head(top_n)